package designparttern.singleton;

/**
 * 虽然上述{@link DoubleCheck}加锁操作避免了线程安全
 * 但是由于 instance = new Object() 这个操作并不是一个原子化操作.而是由一下三步构成
 * 1. 分配该对象的内存空间
 * 2. 初始化对象,调用构造器
 * 3. 将该对象赋值给引用.
 *
 * 而某些编译器为了性能原因可能将 2 3 步进行指令重排
 * 1. 分配该对象的内存空间
 * 2. 将该对象赋值给引用.
 * 3. 初始化对象,调用构造器
 *
 * 这样就导致,该对象实际还没有初始化完毕,但是可能另一个线程已经开始使用该对象,造成不可预知的后果
 */
class DoubleCheck1 {
    /**
     * 解决方案一: 使用 volatile 禁止指令重排序.针对与该变量所有的读操作应该在初始化之后
     */
    private static volatile DoubleCheck1 INSTANCE;
    private static final Object LOCK = new Object();

    private DoubleCheck1() {
    }

    private static DoubleCheck1 getInstance() {
        if (INSTANCE == null) {
            synchronized (LOCK) {
                /**
                 * 解决方案二: 中间变量法,使用中间变量.这样赋值给INSTANCE的对象就是初始化好的对象了
                 */
                DoubleCheck1 temp = new DoubleCheck1();
                INSTANCE = temp;
            }
        }
        return INSTANCE;
    }
}